package com.ibeeking.found.file.rest.controller.v1;

import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.found.file.rest.service.IFileService;
import com.ibeeking.found.file.rest.service.IFiletransferService;
import com.ibeeking.found.file.rest.service.IUserFileService;
import com.ibeeking.found.file.rest.service.component.FileDealComp;
import com.ibeeking.found.file.rest.service.impl.StorageServiceImpl;
import com.ibeeking.found.file.rest.service.util.QiwenFile;
import com.ibeeking.found.file.service.common.dos.FileDO;
import com.ibeeking.found.file.service.common.dos.StorageDO;
import com.ibeeking.found.file.service.common.dos.UserFileDO;
import com.ibeeking.found.file.service.common.param.BatchDownloadFileParam;
import com.ibeeking.found.file.service.common.param.DownloadFileParam;
import com.ibeeking.found.file.service.common.param.PreviewParam;
import com.ibeeking.found.file.service.common.param.UploadFileParam;
import com.ibeeking.found.file.service.common.vo.UploadFileVO;
import com.ibeeking.nematos.constants.enums.OperateLogTypeEnum;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.file.oss.factory.FileOpFactory;
import com.ibeeking.nematos.file.oss.operation.download.Downloader;
import com.ibeeking.nematos.file.oss.operation.download.domain.DownloadFile;
import com.ibeeking.nematos.file.oss.operation.download.domain.Range;
import com.ibeeking.nematos.file.oss.util.FileOpUtils;
import com.ibeeking.nematos.log.annotation.Log;
import com.ibeeking.nematos.utils.file.MimeTypeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
 * @ClassName FriendsController
 * @Description 该接口为文件传输接口，主要用来做文件的上传、下载和预览
 * @Author ibeeking
 * @Date 2021-06-02 18:15
 **/

@Slf4j
@RestController
@RequestMapping("/filetransfer/v1")
public class FiletransferController {

    @Resource
    private IFiletransferService fileTransferServiceImpl;

    @Resource
    private IFileService fileServiceImpl;

    @Resource
    private IUserFileService userFileServiceImpl;

    @Resource
    private FileDealComp fileDealComp;

    @Resource
    private StorageServiceImpl storageServiceImpl;

    @Resource
    private FileOpFactory fileOpFactory;

    public static final String CURRENT_MODULE = "文件传输接口";

    @Log(logType = OperateLogTypeEnum.SAVE, describe = "极速上传")
    @GetMapping(value = "/uploadfile")
    public UploadFileVO uploadFileSpeed(UploadFileParam uploadFileDto) {

        Long userId = UserUtils.getUserId();
        boolean isCheckSuccess = storageServiceImpl.checkStorage(userId, uploadFileDto.getTotalSize());
        if (!isCheckSuccess) {
            throw new BusinessException("存储空间不足");
        }
        UploadFileVO uploadFileVo = fileTransferServiceImpl.uploadFileSpeed(uploadFileDto);
        return uploadFileVo;

    }

    @Log(logType = OperateLogTypeEnum.SAVE, describe = "上传文件")
    @PostMapping(value = "/uploadfile")
    public UploadFileVO uploadFile(HttpServletRequest request, UploadFileParam uploadFileDto) {
        Long userId = UserUtils.getUserId();

        fileTransferServiceImpl.uploadFile(request, uploadFileDto, userId);

        UploadFileVO uploadFileVo = new UploadFileVO();
        return uploadFileVo;

    }


    @Log(logType = OperateLogTypeEnum.QUERY, describe = "下载文件")
    @GetMapping(value = "/downloadfile")
    public void downloadFile(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, DownloadFileParam downloadFileDTO) {
        Cookie[] cookieArr = httpServletRequest.getCookies();
        String token = "";
        if (cookieArr != null) {
            for (Cookie cookie : cookieArr) {
                if ("token".equals(cookie.getName())) {
                    token = cookie.getValue();
                }
            }
        }
        boolean authResult = fileDealComp.checkAuthDownloadAndPreview(downloadFileDTO.getShareBatchNum(),
                downloadFileDTO.getExtractionCode(),
                token,
                downloadFileDTO.getUserFileId(), null);
        if (!authResult) {
            log.error("没有权限下载！！！");
            return;
        }
        httpServletResponse.setContentType("application/force-download");// 设置强制下载不打开
        UserFileDO userFile = userFileServiceImpl.getById(downloadFileDTO.getUserFileId());
        String fileName = "";
        if (userFile.getIsDir() == 1) {
            fileName = userFile.getFileName() + ".zip";
        } else {
            fileName = userFile.getFileName() + "." + userFile.getExtendName();

        }
        try {
            fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        httpServletResponse.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 设置文件名

        fileTransferServiceImpl.downloadFile(httpServletResponse, downloadFileDTO);
    }

    @Log(logType = OperateLogTypeEnum.QUERY, describe = "批量下载文件")
    @GetMapping(value = "/batchDownloadFile")
    public void batchDownloadFile(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BatchDownloadFileParam batchDownloadFileDTO) {
        Cookie[] cookieArr = httpServletRequest.getCookies();
        String token = "";
        if (cookieArr != null) {
            for (Cookie cookie : cookieArr) {
                if ("token".equals(cookie.getName())) {
                    token = cookie.getValue();
                }
            }
        }
        boolean authResult = fileDealComp.checkAuthDownloadAndPreview(batchDownloadFileDTO.getShareBatchNum(),
                batchDownloadFileDTO.getExtractionCode(),
                token,
                batchDownloadFileDTO.getUserFileIds(), null);
        if (!authResult) {
            log.error("没有权限下载！！！");
            return;
        }

        String files = batchDownloadFileDTO.getUserFileIds();
        String[] userFileIdStrs = files.split(",");
        List<Long> userFileIds = new ArrayList<>();
        for(String userFileId : userFileIdStrs) {
            UserFileDO userFile = userFileServiceImpl.getById(userFileId);
            if (userFile.getIsDir() == 0) {
                userFileIds.add(Long.valueOf(userFileId));
            } else {
                QiwenFile qiwenFile = new QiwenFile(userFile.getFilePath(), userFile.getFileName(), true);
                List<UserFileDO> userFileList = userFileServiceImpl.selectUserFileByLikeRightFilePath(qiwenFile.getPath(), userFile.getUserId());
                List<Long> userFileIds1 = userFileList.stream().map(UserFileDO::getUserFileId).collect(Collectors.toList());
                userFileIds.add(userFile.getUserFileId());
                userFileIds.addAll(userFileIds1);
            }
            
        }
        UserFileDO userFile = userFileServiceImpl.getById(userFileIdStrs[0]);
        httpServletResponse.setContentType("application/force-download");// 设置强制下载不打开
        Date date = new Date();
        String fileName = String.valueOf(date.getTime());
        httpServletResponse.addHeader("Content-Disposition", "attachment;fileName=" + fileName + ".zip");// 设置文件名
        fileTransferServiceImpl.downloadUserFileList(httpServletResponse, userFile.getFilePath(), fileName, userFileIds);
    }

    @Log(logType = OperateLogTypeEnum.QUERY, describe = "预览文件")
    @GetMapping("/preview")
    public void preview(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,  PreviewParam previewDTO) throws IOException {
        if (previewDTO.getPlatform() != null && previewDTO.getPlatform() == 2) {
            fileTransferServiceImpl.previewPictureFile(httpServletResponse, previewDTO);
            return ;
        }
        String token = "";
        if (StringUtils.isNotEmpty(previewDTO.getToken())) {
            token = previewDTO.getToken();
        } else {
            Cookie[] cookieArr = httpServletRequest.getCookies();
            if (cookieArr != null) {
                for (Cookie cookie : cookieArr) {
                    if ("token".equals(cookie.getName())) {
                        token = cookie.getValue();
                    }
                }
            }
        }
        UserFileDO userFile = userFileServiceImpl.getById(previewDTO.getUserFileId());
        boolean authResult = fileDealComp.checkAuthDownloadAndPreview(previewDTO.getShareBatchNum(), previewDTO.getExtractionCode(), token, previewDTO.getUserFileId(), previewDTO.getPlatform());
        if (!authResult) {
            log.error("没有权限预览！！！");
            return;
        }
        String fileName = userFile.getFileName() + "." + userFile.getExtendName();
        try {
            fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        httpServletResponse.addHeader("Content-Disposition", "fileName=" + fileName);// 设置文件名
        String mime = MimeTypeUtils.getContentType(userFile.getExtendName());
        httpServletResponse.setHeader("Content-Type", mime);
        if (FileOpUtils.isImageFile(userFile.getExtendName())) {
            httpServletResponse.setHeader("cache-control", "public");
        }
        FileDO fileBean = fileServiceImpl.getById(userFile.getFileId());
        if (FileOpUtils.isVideoFile(userFile.getExtendName()) || "mp3".equalsIgnoreCase(userFile.getExtendName()) || "flac".equalsIgnoreCase(userFile.getExtendName())) {
            //获取从那个字节开始读取文件
            String rangeString = httpServletRequest.getHeader("Range");
            int start = 0;
            if (StringUtils.isNotBlank(rangeString)) {
                start = Integer.parseInt(rangeString.substring(rangeString.indexOf("=") + 1, rangeString.indexOf("-")));
            }
            Downloader downloader = fileOpFactory.getDownloader(fileBean.getStorageType());
            DownloadFile downloadFile = new DownloadFile();
            downloadFile.setFileUrl(fileBean.getFileUrl());
            Range range = new Range();
            range.setStart(start);
            if (start + 1024 * 1024 * 1 >= fileBean.getFileSize().intValue()) {
                range.setLength(fileBean.getFileSize().intValue() - start);
            } else {
                range.setLength(1024 * 1024 * 1);
            }
            downloadFile.setRange(range);
            InputStream inputStream = downloader.getInputStream(downloadFile);
            OutputStream outputStream = httpServletResponse.getOutputStream();
            try {
                //返回码需要为206，代表只处理了部分请求，响应了部分数据
                httpServletResponse.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                // 每次请求只返回1MB的视频流
                httpServletResponse.setHeader("Accept-Ranges", "bytes");
                //设置此次相应返回的数据范围
                httpServletResponse.setHeader("Content-Range", "bytes " + start + "-" + (fileBean.getFileSize() - 1) + "/" + fileBean.getFileSize());
                IOUtils.copy(inputStream, outputStream);
            } finally {
                IOUtils.closeQuietly(inputStream);
                IOUtils.closeQuietly(outputStream);
                if (downloadFile.getOssClient() != null) {
                    downloadFile.getOssClient().shutdown();
                }
            }
        } else {
            fileTransferServiceImpl.previewFile(httpServletResponse, previewDTO);
        }

    }

    @Log(logType = OperateLogTypeEnum.QUERY, describe = "获取存储信息")
    @GetMapping(value = "/getstorage")
    public StorageDO getStorage() {
        Long userId = UserUtils.getUserId();
        StorageDO storageBean = new StorageDO();
        storageBean.setUserId(userId);
        Long storageSize = fileTransferServiceImpl.selectStorageSizeByUserId(userId);
        StorageDO storage = new StorageDO();
        storage.setUserId(userId);
        storage.setStorageSize(storageSize);
        Long totalStorageSize = storageServiceImpl.getTotalStorageSize(userId);
        storage.setTotalStorageSize(totalStorageSize);
        return storage;

    }


}
